/*******************************************************************************
 File Name        : freyabasecontrol.h
 Summary          : FreyaLib`s control
 Create           : 2015-04-27
 Author           : Schindleren
 Update history   :
 NO.     Author        Date         Content
 001     Schindleren   2015-04-27   Create New
 002     Schindleren   2022-11-27   Add funcation AppendCmdLogString
 003     Schindleren   2023-03-28   Swap QSemaphore create and m_CMDDistribution.InsertData in query data
*******************************************************************************/
#ifndef FREYABASECONTROL_H
#define FREYABASECONTROL_H

#include "freyalib_global.h"
#include "freyaabstractcontrol.h"
#include "freyapublicregister.h"
#include "freyacommanddistribution.h"

#include <vector>
#include <QDebug>
#include <QTimer>
#include <QEventLoop>

#define CUSTOMCLSTOVARIANT(pObject)             QVariant::fromValue((void*)pObject)
#define VARIANTTOCUSTOMCLS(pObject, ClassName)  static_cast<ClassName*>(pObject.value<void*>())

#define FREYA_REQUESTEXECUTION_NON              FreyaBaseControl::GetFreyaControl()->RequestExecution(this)
#define FREYA_REQUESTEXECUTION(data)            FreyaBaseControl::GetFreyaControl()->RequestExecution(data, this, 0)

#define FREYA_QUERYEXECUTION(data)              FreyaBaseControl::GetFreyaControl()->RequestExecution(data, this, 2000)
#define FREYA_REPLYEXECUTION(data)              FreyaBaseControl::GetFreyaControl()->ReplyExecution(data, this)

class FreyaPublicRegister;
class FreyaBaseAction;
class FREYALIBSHARED_EXPORT FreyaBaseControl : public FreyaAbstractControl
{
    friend class FreyaCommandDistribution;
private:
    explicit FreyaBaseControl();

public:
    QString FreyaVersion();

    ~FreyaBaseControl();

    QVariantMap GetConfigFromFile(const QString &filePath);
    bool SetConfigToFile(const QString &filePath, const QVariantMap &varmap);
    QVariant GetConfig(const QStringList &configPath);
    bool SetConfig(const QStringList &configPath, const QVariant &var);
    bool InsertConfig(const QStringList &configPath, const QVariant &var);
    bool RemoveConfig(const QStringList &configPath);

    /***************************************************
      Author: Schindleren
      Date: 2015-04-27
      Description: register action.
      Input: FreyaBaseAction *actObject, const char *actionName
      Output: void
      Return: bool
    ****************************************************/
    bool RegisterObject(FreyaBaseAction *actObject, const char *actionName);

    /***************************************************
      Author: Schindleren
      Date: 2015-04-27
      Description: unregister action by action name.
      Input: const QString &actionName
      Output: void
      Return: bool
    ****************************************************/
    bool UnRegisterObject(const QString &actionName);

    /***************************************************
      Author: Schindleren
      Date: 2015-04-27
      Description: unregister action.
      Input: FreyaBaseAction *actObject
      Output: void
      Return: bool
    ****************************************************/
    bool UnRegisterObject(FreyaBaseAction *actObject);

    /***************************************************
      Author: Schindleren
      Date: 2015-04-27
      Description: connect action with commands.
      Input: FreyaBaseAction *actObject, QList<quint64> commandList
      Output: void
      Return: bool
    ****************************************************/
    bool RegisterCommand(FreyaBaseAction *actObject, QList<quint64> commandList);

    /***************************************************
      Author: Schindleren
      Date: 2015-04-27
      Description: find action object pointer by action name.
      Input: const QString &actionName
      Output: void
      Return: FreyaBaseAction*
    ****************************************************/
    bool UnRegisterCommand(FreyaBaseAction *actObject);

    /***************************************************
      Author: Schindleren
      Date: 2015-04-27
      Description: find action object pointer by action name.
      Input: const QString &actionName
      Output: void
      Return: FreyaBaseAction*
    ****************************************************/
    QList<FreyaBaseAction *> FindActionObject(const QString &actionName);

    /***************************************************
      Author: Schindleren
      Date: 2015-04-27
      Description: find action name by object pointer.
      Input: FreyaBaseAction *actObject
      Output: void
      Return: QString
    ****************************************************/
    QString FindActionName(FreyaBaseAction *actObject);

    /***************************************************
      Author: Schindleren
      Date: 2015-04-27
      Description: Delete all actions which registed in this control,but except objects.
      Input: const QList<FreyaBaseAction*> &except = QList<FreyaBaseAction*>()
      Output: void
      Return: void
    ****************************************************/
    void DeleteAllAction(const QList<FreyaBaseAction*> &except = QList<FreyaBaseAction*>());

    /***************************************************
      Author: Schindleren
      Date: 2015-04-27
      Description: Delete all actions which registed in this control,but except object.
      Input: const QStringList &except
      Output: void
      Return: void
    ****************************************************/
    void DeleteAllAction(const QStringList &except);

    /***************************************************
      Author: Schindleren
      Date: 2015-04-27
      Description: Insert FreyaData to control`s cache.
      Input: const FreyaData pData
      Output: void
      Return: bool
    ****************************************************/
    bool InsertFreyaData(const FreyaData pData);

    /***************************************************
      Author: Schindleren
      Date: 2015-04-27
      Description: Get FreyaData from Inserted by dataID.
      Input: const QString &dataID
      Output: void
      Return: FreyaData
    ****************************************************/
    FreyaData FindFreyaData(const QString &dataID);

    /***************************************************
      Author: Schindleren
      Date: 2015-04-27
      Description: Get FreyaData from Inserted by dataID, then remove it.
      Input: const QString &dataID
      Output: void
      Return: FreyaData
    ****************************************************/
    FreyaData TakeFreyaData(const QString &dataID);

    /***************************************************
      Author: Schindleren
      Date: 2015-04-27
      Description: Execution with no arguments.
                    If is query, its whill return in 'msec' mile seconds, or has answer.
      Input: const FreyaData BaseData, void *pRequester = nullptr, int msec = 0
      Output: void
      Return: bool
    ****************************************************/
    bool RequestExecution(void *pRequester = nullptr);

    /***************************************************
      Author: Schindleren
      Date: 2015-04-27
      Description: Execution with command.
                    If is query, its whill return in 'msec' mile seconds, or has answer.
      Input: const FreyaData BaseData, void *pRequester = nullptr, int msec = 0
      Output: void
      Return: bool
    ****************************************************/
    bool RequestExecution(const quint64 &command, void *pRequester = nullptr, int msec = 0);

    /***************************************************
      Author: Schindleren
      Date: 2015-04-27
      Description: Execution with FreyaData.
                    If is query, its whill return in 'msec' mile seconds, or has answer.
      Input: const FreyaData BaseData, void *pRequester = nullptr, int msec = 0
      Output: void
      Return: bool
    ****************************************************/
    bool RequestExecution(const FreyaData pData, void *pRequester = nullptr, int msec = 0);

    /***************************************************
      Author: Schindleren
      Date: 2019-11-01
      Description: Reply the query execution with FreyaData.
      Input: const FreyaData BaseData, void *pRequester = nullptr
      Output: void
      Return: bool
    ****************************************************/
    bool ReplyExecution(const FreyaData pData, void *pRequester = nullptr);

    /***************************************************
      Author: Schindleren
      Date: 2015-04-27
      Description: Execution requester object.
      Input: void
      Output: void
      Return: void*
    ****************************************************/
    void *FreyaRequester() {return m_pRequester;}

    /***************************************************
      Author: Schindleren
      Date: 2019-10-29
      Description: Get execution requester object from BaseData.
      Input: const FreyaData
      Output: void
      Return: void*
    ****************************************************/
    void *FreyaRequester(const FreyaData BaseData) {return VARIANTTOCUSTOMCLS(BaseData->GetProperty(FREYALIB_FLG_REQUESTER), void);}

    void AppendCmdLogString(const quint64 &command, const QString &LogStr);
    inline QString CmdLogString(const quint64 &command)
    {
        return m_FreyaPublicRegister.CmdLogString(command);
    }

private:
    void                                *m_pRequester;
    FreyaPublicRegister                 m_FreyaPublicRegister;
    FreyaCommandDistribution            m_CMDDistribution;

public:
    /***************************************************
      Author: Schindleren
      Date: 2015-04-27
      Description: FreyaControl always be single case
      Input: FreyaBaseControl *pOtherControl = nullptr
      Output: void
      Return: FreyaBaseControl*
    ****************************************************/
    static FreyaBaseControl *GetFreyaControl(FreyaBaseControl *pOtherControl = nullptr)
    {
        static FreyaBaseControl *s_pFreyaBaseControl = nullptr;
        if(nullptr == pOtherControl)
        {
            if(nullptr == s_pFreyaBaseControl)
            {
                s_pFreyaBaseControl = new FreyaBaseControl();
                qInfo() << "FreyaLib > " << "Structure FreyaBaseControl" << s_pFreyaBaseControl;
            }
        }
        else
        {
            qInfo() << "FreyaLib > " << "SetFreyaControl" << pOtherControl;
            if(nullptr != s_pFreyaBaseControl && s_pFreyaBaseControl != pOtherControl)
            {
                delete s_pFreyaBaseControl;
                s_pFreyaBaseControl = nullptr;
            }
            s_pFreyaBaseControl = pOtherControl;
        }
        return s_pFreyaBaseControl;
    }
};

#endif // FREYABASECONTROL_H
